package com.xiaoshu.test.rpc.netty.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.xiaoshu.test.rpc.netty.server.ClassInfo;
import com.xiaoshu.test.service.HelloRpcService;
import com.xiaoshu.test.service.HelloRpcServiceImpl;

public class NettyRpcProxyMain {
	
	public static void main(String[] args) {
		HelloRpcService helloService = new HelloRpcServiceImpl();
		HelloRpcService helloRpc = NettyRpcProxyMain.proxy(helloService);
		helloRpc.showName(" deane");
	}

	@SuppressWarnings("unchecked")
	public static <T> T proxy(final Object target){
		return (T)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				ClassInfo classInfo = new ClassInfo();
				classInfo.setClassName(target.getClass().getName());
				
				classInfo.setMethodName(method.getName());
				classInfo.setParameterTypes(method.getParameterTypes());
				classInfo.setArgs(args);
				
				final RestHandler restHandler = new RestHandler();
				EventLoopGroup group = new NioEventLoopGroup();
				try {
					Bootstrap server = new Bootstrap();
					server.group(group)
						.channel(NioSocketChannel.class)
						.option(ChannelOption.TCP_NODELAY, true)   
						.handler(new ChannelInitializer<Channel>() {

							@Override
							protected void initChannel(Channel ch) throws Exception {
								  ChannelPipeline pipeline = ch.pipeline();    
		                             pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));    
		                             pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));    
		                             pipeline.addLast("encoder", new ObjectEncoder());      
		                             pipeline.addLast("decoder", new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));    
		                             pipeline.addLast("handler",restHandler);  
							}
							
						});
					
					ChannelFuture future = server.connect("localhost", 8080).sync();
					future.channel().writeAndFlush(classInfo).sync();
					future.channel().closeFuture().sync();
				} catch (Exception e) {
					e.printStackTrace();
				} finally{
					group.shutdownGracefully();
				}
				return restHandler.getResponse();
			}
		});
	}
	
}
